package cn.kgm.sqlSession;

import cn.kgm.executor.Executor;
import cn.kgm.pojo.Configuration;
import cn.kgm.pojo.MappedStatement;

import java.lang.reflect.*;
import java.sql.SQLException;
import java.util.List;

public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;

    private Executor executor;

    public DefaultSqlSession(Configuration configuration, Executor executor) {
        this.configuration = configuration;
        this.executor = executor;
    }

    /**
     * 将查询操作委派给执行器
     *
     * @param statementId
     * @param param
     * @param <E>
     * @return
     */
    @Override
    public <E> List<E> selectList(String statementId, Object param) throws Exception {
        // executor.query() 就是去调用jdbc 需要:[1,数据库配置信息,2,sql配置信息]
        List<E> results = executor.query(configuration, configuration.get(statementId), param);
        return results;
    }

    @Override
    public <T> T selectOne(String statementId, Object param) throws Exception {
        List<Object> results = this.selectList(statementId, param);
        if (results.size() == 1) {
            return (T) results.get(0);
        } else if (results.size() > 1) {
            throw new RuntimeException("预期一条数据,但是查出多条!");
        }
        return null;
    }

    @Override
    public void close() throws SQLException {
        executor.close();
    }

    @Override
    public <T> T getMapper(Class<?> clazz) {
        Object proxy = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{clazz}, new InvocationHandler() {
            /**
             * proxy 代理对象的引用(很少用)
             * method 当前被调用的方法的字节码对象
             * args 调用当前放大需要的参数
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                /**
                 * 具体的逻辑还是执行jdbc
                 * 通过调用sqlSession里面的方法来完成方法调用
                 * 参数准备:1.statementId:cn.kgm.dao.IUserDao 2,param
                 */
                // 获取方法名
                String methodName = method.getName();
                // 获取方法所在的类的全路径名
                String declaringName = method.getDeclaringClass().getName();
                String statementId = declaringName.concat(".").concat(methodName);
                MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
                // select/update/delete/insert
                String sqlCommandType = mappedStatement.getSqlCommandType();
                switch (sqlCommandType) {
                    case "select":
                        // 查询
                        // 获取当前调用的方法的返回值类型
                        Type genericReturnType = method.getGenericReturnType();
                        // 判断返回值类型是否实现了 泛型类型参数化
                        // 就是简单判断一下,返回值里面有没有泛型
                        // 如果有泛型先默认他为集合类型
                        if (genericReturnType instanceof ParameterizedType) {
                            if (args != null) {
                                return selectList(statementId, args[0]);
                            }
                            return selectList(statementId, null);
                        }
                        return selectOne(statementId, args[0]);
                    case "update":
                        //更新
                        break;
                    case "insert":
                        // 插入
                        break;
                    case "delete":
                        //删除
                        break;
                    default:
                        throw new RuntimeException("为止的查询类型[" + sqlCommandType + "]");
                }
                return null;
            }
        });
        return (T) proxy;
    }
}
